/**
 * Created with JetBrains WebStorm.
 * User: Ender
 * Date: 6/2/13
 * Time: 6:48 PM
 * To change this template use File | Settings | File Templates.
 */

'use strict';

angular.module('ender.boardgames.reversi', [])
    .factory('reversiGame', function () {

        var customRules = [
            {
                id: "initialSetup",
                name: "Initial setup",
                type: "choice",
                values: ['horizontal', 'diagonal'],
                default: 'horizontal'
            }
        ];
        var ruleValues = {};
        var boardSize = {
            size: 8
        };

        function getPiecesInDirection(board, rowIndex, columnIndex, direction) {
            var left = direction == 'left' || direction == 'upper-left' || direction == 'lower-left';
            var right = direction == 'right' || direction == 'upper-right' || direction == 'lower-right';
            var up = direction == 'up' || direction == 'upper-left' || direction == 'upper-right';
            var down = direction == 'down' || direction == 'lower-left' || direction == 'lower-right';

            function getNextRowIndex(rowIndex) {
                if (up)
                    return rowIndex - 1;
                if (down)
                    return rowIndex + 1;
                return rowIndex;
            }

            function getNextColumnIndex(columnIndex) {
                if (left)
                    return columnIndex - 1;
                if (right)
                    return columnIndex + 1;
                return columnIndex;
            }

            var cells = [];
            var cellHasDisc = false;
            do {
                var rowIndex = getNextRowIndex(rowIndex);
                var columnIndex = getNextColumnIndex(columnIndex);
                cellHasDisc = board[rowIndex] && board[rowIndex][columnIndex] && board[rowIndex][columnIndex].color;
                if (cellHasDisc)
                    cells.push(board[rowIndex][columnIndex]);
            } while (cellHasDisc);

            return cells;

        };


        return {
            name: "Reversi/Othello",
            customRules: customRules,
            boardSize: boardSize,
            hasScore: true,
            canBlockPlayer: true,
            preProcessBoard: function (board, players) {
                if (ruleValues.initialSetup == 'diagonal') {
                    diagonalSetup(board);
                } else if (ruleValues.initialSetup == 'horizontal') {
                    horizontalSetup(board);
                }

                function diagonalSetup(board) {
                    // TODO generalize for larger boards
                    board[3][3].color = players[1].color;
                    board[3][4].color = players[0].color;
                    board[4][4].color = players[1].color;
                    board[4][3].color = players[0].color;
                }

                function horizontalSetup(board) {
                    // TODO generalize for larger boards
                    board[3][3].color = players[1].color;
                    board[3][4].color = players[1].color;
                    board[4][4].color = players[0].color;
                    board[4][3].color = players[0].color;
                }
            },
            processRules: function (rules) {
                rules = rules || customRules;

                ruleValues = {};
                for (var i = 0; i < rules.length; i++) {
                    var gameRule = rules[i];
                    ruleValues[gameRule.id] = gameRule.value || gameRule.default;
                }
            },
            processPlayers: function (players) {
                players[0].color = 'black';
                players[1].color = 'white';
            },
            checkVictory: function (board, players) {

                if (isBoardFull(board)) {
                    return this.evaluateVictory(board, players)
                }

                function isBoardFull(board) {
                    for (var row = 0; row < board.length; row++) {
                        for (var column = 0; column < board[row].length; column++) {
                            if (!board[row][column].color)
                                return false;
                        }
                    }
                    return true;
                }
            },
            processCellClicked: function (board, row, column, currentPlayer) {
                board[row][column].color = currentPlayer.color;
                capturePieces(board, row, column);

                function capturePieces(board, rowIndex, columnIndex) {
                    var directions = [ 'left', 'right', 'up', 'down', 'upper-left', 'lower-left', 'upper-right', 'lower-right' ];
                    for (var i = 0; i < directions.length; i++) {
                        var cells = getPiecesInDirection(board, rowIndex, columnIndex, directions[i]);
                        // if neighbor belongs to other player
                        if (cells.length > 1 && cells[0].color !== currentPlayer.color) {
                            for (var j = 1; j < cells.length; j++)
                                // look for cell belonging to current player
                                if (cells[j].color === currentPlayer.color) {
                                    // turn cells between
                                    for (var k = 0; k < j; k++) {
                                        cells[k].color = currentPlayer.color;
                                    }
                                    break;
                                }
                        }
                    }
                }
            },
            resetScore: function (players) {
                players[0].score = 0;
                players[1].score = 0;
            },
            isLegalMove: function (board, rowIndex, columnIndex, currentPlayer) {
                var directions = [ 'left', 'right', 'up', 'down', 'upper-left', 'lower-left', 'upper-right', 'lower-right' ];
                for (var i = 0; i < directions.length; i++) {
                    var cells = getPiecesInDirection(board, rowIndex, columnIndex, directions[i]);
                    // if neighbor belongs to other player
                    if (cells.length > 1 && cells[0].color !== currentPlayer.color) {
                        for (var j = 1; j < cells.length; j++)
                            // look for cell belonging to current player
                            if (cells[j].color === currentPlayer.color)
                                return true;
                    }
                }

                return false;
            },
            updateScore: function (board, players) {
                for (var i = 0; i < players.length; i++) {
                    var player = players[i];
                    var score = 0;
                    for (var row = 0; row < board.length; row++) {
                        for (var column = 0; column < board[row].length; column++) {
                            if (board[row][column].color === player.color)
                                score++;
                        }
                    }
                    player.score = score;
                }
            },
            playerCanMove: function (board, player) {
                var gameLogic = this;
                for (var row = 0; row < board.length; row++) {
                    for (var column = 0; column < board[row].length; column++) {
                        if ((!board[row][column].color) && gameLogic.isLegalMove(board, row, column, player)) {
                            return true;
                        }
                    }
                }
                return false;
            },
            evaluateVictory: function (board, players) {
                if (players[0].score === players[1].score)
                    return 'draw';
                if (players[0].score > players[1].score)
                    return players[0];
                if (players[0].score < players[1].score)
                    return players[1];
            },
            getClassForCell: function () {
                return 'end-boardgame-reversi-cell';
            },
            getClassForPlayerIndicator: function () {
                return 'end-boardgame-reversi-player-indicator';
            }
        }
    })
    .directive('endBoardgameReversiCell', function factoryFunction() {
        return {
            restrict: 'C',
            link: function (scope, element, attrs) {
                scope.$watch('cell.color', function (newColor, oldColor) {
                    if (newColor) {
                        element.html('<div class="circle ' + newColor + '"></div>');
                    }
                });
            }
        };
    })
    .directive('endBoardgameReversiPlayerIndicator', function factoryFunction() {
        return {
            restrict: 'C',
            link: function (scope, element, attrs) {
                scope.$watch('player.color', function (newColor) {
                    if (newColor) {
                        element.addClass('circle').css('background-color', newColor);
                    }
                });
            }
        };
    });
